---
title: Auth
sidebar:
  order: 21
---
import PassAuthPayloadSnippet from '../../_assets/code/patterns/auth/pass-auth-payload.ts?snippet'
import LiveStoreProviderSnippet from '../../_assets/code/patterns/auth/live-store-provider.tsx?snippet'
import KeepPayloadCanonicalSnippet from '../../_assets/code/patterns/auth/keep-payload-canonical.ts?snippet'


LiveStore doesn't include built-in authentication or authorization support, but you can implement it in your app's logic.

## Pass an auth payload to the sync backend

Use the `syncPayload` store option to send a custom payload to your sync backend.

### Example

The following example sends the authenticated user's JWT to the server.

<LiveStoreProviderSnippet />

On the sync server, validate the token and allow or reject the sync based on the result. See the following example:

<PassAuthPayloadSnippet />

The above example uses [`jose`](https://www.npmjs.com/package/jose), a popular JavaScript module that supports JWTs. It works across various runtimes, including Node.js, Cloudflare Workers, Deno, Bun, and others.

The `validatePayload` function receives the `authToken`, checks if the payload exists, and verifies that it's valid and hasn't expired. If all checks pass, sync continues as normal. If any check fails, the server rejects the sync.

The client app still works as expected, but saves data locally. If the user re-authenticates or refreshes the token later, LiveStore syncs any local changes made while the user was unauthenticated.

## Re-validate payload inside the Durable Object

When you rely on `syncPayload`, treat it as untrusted input. Decode the token inside `validatePayload` to gate the connection, and then repeat the same verification inside the Durable Object before trusting per-push metadata.

<KeepPayloadCanonicalSnippet />

- `validatePayload` runs once per connection and rejects mismatched tokens before LiveStore upgrades to WebSocket.
- `onPush` (and `onPull`, if you need it) must repeat the verification because the payload forwarded to the Durable Object is the original client input.
- The HTTP transport does not forward payloads today; embed the necessary authorization context directly in the events or move those clients to WebSocket/DO-RPC if you must rely on shared payload metadata.

You can extend `ensureAuthorized` to project additional claims, memoise verification per `authToken`, or enforce application-specific policies without changing LiveStore internals.

## Client identity vs user identity

LiveStore's `clientId` identifies a client instance, while user identity is an application-level concern that must be modeled through your application's events and logic.

### Key points
- `clientId`: Automatically managed by LiveStore, identifies a client instance
- User identity: Managed by your application through events and syncPayload

### Using syncPayload for authentication

The `syncPayload` is primarily intended for authentication purposes:

<LiveStoreProviderSnippet />

User identification and semantic data (like user IDs) should typically be handled through your event payloads and application state rather than relying solely on the sync payload.
